package com.wellsoft.pt.app.dingtalk.utils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiCallBackGetCallBackFailedResultRequest;
import com.dingtalk.api.request.OapiCallBackRegisterCallBackRequest;
import com.dingtalk.api.request.OapiDepartmentGetRequest;
import com.dingtalk.api.request.OapiDepartmentListRequest;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiUserGetRequest;
import com.dingtalk.api.request.OapiUserListbypageRequest;
import com.dingtalk.api.request.OapiWorkrecordAddRequest;
import com.dingtalk.api.request.OapiWorkrecordAddRequest.FormItemVo;
import com.dingtalk.api.request.OapiWorkrecordUpdateRequest;
import com.dingtalk.api.response.OapiCallBackGetCallBackFailedResultResponse;
import com.dingtalk.api.response.OapiCallBackRegisterCallBackResponse;
import com.dingtalk.api.response.OapiDepartmentGetResponse;
import com.dingtalk.api.response.OapiDepartmentListResponse;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiUserGetResponse;
import com.dingtalk.api.response.OapiUserListbypageResponse;
import com.dingtalk.api.response.OapiWorkrecordAddResponse;
import com.dingtalk.api.response.OapiWorkrecordUpdateResponse;
import com.taobao.api.ApiException;
import com.wellsoft.context.enums.ModuleID;
import com.wellsoft.context.util.ApplicationContextHolder;
import com.wellsoft.context.util.json.JsonUtils;
import com.wellsoft.pt.app.dingtalk.constants.Constants;
import com.wellsoft.pt.app.dingtalk.constants.DingTalkApis;
import com.wellsoft.pt.app.dingtalk.constants.DingTalkInfo;
import com.wellsoft.pt.app.dingtalk.entity.WorkRecord;
import com.wellsoft.pt.app.dingtalk.enums.EnumDingtalkMsgType;
import com.wellsoft.pt.app.dingtalk.service.WorkRecordService;
import com.wellsoft.pt.cache.Cache;
import com.wellsoft.pt.cache.CacheManager;
import com.wellsoft.pt.security.util.JwtTokenUtil;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import net.sf.json.JSONObject;

/**
 * Description: 钉钉接口API工具类
 *  
 * @author Well
 * @date 2020年5月29日
 * @version 1.0
 * 
 * <pre>
 * 修改记录:
 * 修改后版本	修改人		修改日期			修改内容
 * 2020年5月29日.1	Well		2020年5月29日		Create
 * </pre>
 *
 */
public abstract class DingtalkApiUtils {

	private static Logger logger = LoggerFactory.getLogger(DingtalkApiUtils.class);

	private static Cache cache = null;

	private static WorkRecordService workRecordService = null;

	static {
		cache = ApplicationContextHolder.getBean(CacheManager.class).getCache(ModuleID.APP);
		workRecordService = ApplicationContextHolder.getBean(WorkRecordService.class);
	}

	/**
	 * 获取access_token
	 * 
	 * @return
	 */
	public static String getAccessToken() {
		String access_token = ""; // token
		try {
			String token = (String) cache.getValue(Constants.DINGTALK_PT_CACHE_TOKEN);
			if (token != null && !StringUtils.isEmpty(token)) {
				Jws<Claims> Jws = JwtTokenUtil.getClaims(token);
				Claims claims = Jws.getBody();
				access_token = (String) claims.get(Constants.DINGTALK_ACCESS_TOKEN);
				return access_token;
			}
		} catch (ExpiredJwtException e1) {
			e1.printStackTrace();
		}
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_ACCESS_TOKEN);
			OapiGettokenRequest req = new OapiGettokenRequest();
			req.setAppkey(DingTalkInfo.APP_KEY);
			req.setAppsecret(DingTalkInfo.APP_SECRET);
			req.setHttpMethod("GET");
			OapiGettokenResponse rsp = client.execute(req);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			int expires_in = 0; // 过期时间
			if (jb != null) {
				expires_in = jb.getInt("expires_in"); // 过期时间
				access_token = jb.getString("access_token"); // token
				Map<String, Object> body = new HashMap<>();
				body.put(Constants.DINGTALK_ACCESS_TOKEN, access_token);
				long curDateTimeStamp = new Date().getTime() / 1000;
				Date expireDate = new Date(curDateTimeStamp + expires_in - 60); // 60秒为校正值
				String tokenStr = JwtTokenUtil.createToken(body, expireDate); // 把access_token设置在jwt
				cache.put(Constants.DINGTALK_PT_CACHE_TOKEN, tokenStr);
			}
		} catch (ApiException e) {
			logger.error(e.getMessage());
		}
		return access_token;
	}

	/**
	 * 注册回调监听事件
	 * 
	 * @param backTags
	 * @param accessToken
	 */
	public static JSONObject registerCallBack(List<String> backTags, String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_REGISTER_CALL_BACK);
			OapiCallBackRegisterCallBackRequest req = new OapiCallBackRegisterCallBackRequest();
			req.setCallBackTag(backTags);
			req.setToken(DingTalkInfo.EVENT_CALL_BACK_TOKEN);
			req.setAesKey(DingTalkInfo.APP_AES_KEY);
			req.setUrl(DingTalkInfo.CORP_DOMAIN_URI + "mobile/pt/dingtalk/call_back");
			OapiCallBackRegisterCallBackResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			return jb;
		} catch (ApiException e) {
			logger.error(e.getErrMsg());
		}
		return null;
	}

	/**
	 * 获取钉钉用户详情
	 * 
	 * @param userId
	 * @param accessToken
	 */
	public static JSONObject getDingTalkUserInfo(String userId, String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_USER_GET);
			OapiUserGetRequest req = new OapiUserGetRequest();
			req.setUserid(userId);
			req.setHttpMethod("GET");
			OapiUserGetResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			return jb;
		} catch (ApiException e) {
			logger.error(e.getErrMsg());
		}
		return null;
	}

	/**
	 * 获取钉钉部门列表
	 * 
	 * @param userId
	 * @param accessToken
	 */
	public static JSONObject getDingTalkDeptList(String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_DEPARTMENT_LIST);
			OapiDepartmentListRequest req = new OapiDepartmentListRequest();
			req.setHttpMethod("GET");
			OapiDepartmentListResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			return jb;
		} catch (ApiException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取钉钉部门详情
	 * 
	 * @param userId
	 * @param accessToken
	 */
	public static JSONObject getDingTalkDeptInfo(String deptId, String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_DEPARTMENT_GET);
			OapiDepartmentGetRequest req = new OapiDepartmentGetRequest();
			req.setId(deptId);
			req.setHttpMethod("GET");
			OapiDepartmentGetResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			return jb;
		} catch (ApiException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取部门用户详情数据
	 * @param deptId
	 * @param accessToken
	 * @return
	 */
	public static JSONObject getDingTalkUserListbypage(String deptId, String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_USER_LISTBYPAGE);
			OapiUserListbypageRequest req = new OapiUserListbypageRequest();
			req.setDepartmentId(Long.parseLong(deptId));
			req.setOffset(0L);
			req.setSize(100L);
			req.setHttpMethod("GET");
			OapiUserListbypageResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			return jb;
		} catch (ApiException e) {
			logger.warn(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 发起钉钉待办
	 * @param bizId 平台业务id
	 * @param userId 钉钉用户id
	 * @param userName 用户名称
	 * @param accessToken 
	 * @param title 待办标题
	 * @param url 待办跳转url
	 * @param formItemList 待办具体内容
	 * @return
	 */
	public static JSONObject addWorkRecord(String bizId, String userId, String userName, String accessToken,
			String title, String url, List<FormItemVo> formItemList) {
		try {
			Date createTime = new Date();
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_WORKRECORD_ADD);
			OapiWorkrecordAddRequest req = new OapiWorkrecordAddRequest();
			req.setUserid(userId);
			req.setCreateTime(createTime.getTime());
			req.setTimestamp(createTime.getTime());
			req.setTitle(title);
			req.setUrl(url);
			req.setFormItemList(formItemList);
			OapiWorkrecordAddResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			String recordId = jb.getString("record_id");
			WorkRecord record = workRecordService.getWorkRecordByCondition(bizId, userId, recordId);
			if (record == null) {
				record = new WorkRecord();
				record.setBizId(bizId);
				record.setDingRecordId(recordId);
				record.setDingUserId(userId);
			}
			int errcode = jb.getInt("errcode");
			String errmsg = "";
			if (errcode == 0) {
				record.setRecordStatus(0);
			} else {
				if (errcode == 88) {
					errcode = jb.getInt("sub_code");
					errmsg = jb.getString("sub_msg");
				} else {
					errcode = jb.getInt("errcode");
					errmsg = jb.getString("errmsg");
				}
				record.setRecordStatus(1); // 发起待办失败
				record.setErrCode("" + errcode);
				record.setErrMsg(errmsg);
			}
			record.setRecordStatus(1); // 发起待办失败
			record.setOperateTime(new Date());
			record.setTitle(title);
			record.setUrl(url);
			record.setUserName(userName);
			record.setFormItemList(JsonUtils.object2Json(formItemList));
			if (StringUtils.isEmpty(record.getUuid())) {
				workRecordService.save(record);
			} else {
				workRecordService.update(record);
			}
			return jb;
		} catch (ApiException e) {
			logger.warn(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 更新钉钉待办
	 * @param bizId 平台业务id
	 * @param userId 钉钉用户id
	 * @param accessToken 
	 * @return
	 */
	public static JSONObject updateWorkRecord(String bizId, String userId, String accessToken) {
		try {
			WorkRecord record = workRecordService.getWorkRecordByCondition(bizId, userId, null);
			if (record == null) {
				logger.warn("updateWorkRecord bizId[" + bizId + "]userId[" + userId + "] not found record");
				return null;
			}
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_WORKRECORD_UPDATE);
			OapiWorkrecordUpdateRequest req = new OapiWorkrecordUpdateRequest();
			req.setUserid(userId);
			req.setRecordId(record.getDingRecordId());
			OapiWorkrecordUpdateResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			int errcode = jb.getInt("errcode");
			String errmsg = "";
			if (errcode == 0) { // 更新成功，不需要以下操作
				workRecordService.delete(record.getUuid());
				return jb;
			}
			if (errcode == 88) {
				errcode = jb.getInt("sub_code");
				errmsg = jb.getString("sub_msg");
			} else {
				errcode = jb.getInt("errcode");
				errmsg = jb.getString("errmsg");
			}
			record.setOperateTime(new Date());
			record.setRecordStatus(2); // 更新待办失败
			// record.setTitle("");
			// record.setUrl("");
			// record.setUserName(userName);
			record.setErrCode("" + errcode);
			record.setErrMsg(errmsg);
			// record.setFormItemList("");
			workRecordService.update(record);
		} catch (ApiException e) {
			logger.warn(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 工作通知消息
	 * @param useridList 多个以英文逗号“,”隔开
	 * @param msgType 消息类型
	 * @param msgTitle 消息标题，msgType为“link”时使用
	 * @param msgContent 消息内容
	 * @param mediaId 媒介id msgType为“image、file”时使用
	 * @param messageUrl 消息链接，msgType为“link”时使用
	 * @param picUrl 图片链接，msgType为“link”时使用
	 * @param accessToken
	 * @return
	 */
	public static JSONObject sendDingtalkMsg(String useridList, String msgType, String msgTitle, String msgContent,
			String mediaId, String messageUrl, String picUrl, String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_MESSAGE_CORPCONVERSATION);
			OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
			request.setUseridList(useridList);
			request.setAgentId(Long.parseLong(DingTalkInfo.AGENT_ID));
			request.setToAllUser(false);

			OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
			// TODO 根据msgType判断
			switch (msgType) {
			case "text":
				msg.setMsgtype(EnumDingtalkMsgType.text.getValue());
				msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
				msg.getText().setContent(msgContent);
				request.setMsg(msg);
				break;
			case "image":
				msg.setMsgtype(EnumDingtalkMsgType.image.getValue());
				msg.setImage(new OapiMessageCorpconversationAsyncsendV2Request.Image());
				msg.getImage().setMediaId(mediaId);
				request.setMsg(msg);
				break;
			case "file":
				msg.setMsgtype(EnumDingtalkMsgType.file.getValue());
				msg.setFile(new OapiMessageCorpconversationAsyncsendV2Request.File());
				msg.getFile().setMediaId(mediaId);
				request.setMsg(msg);
				break;
			case "link":
				msg.setMsgtype(EnumDingtalkMsgType.link.getValue());
				msg.setLink(new OapiMessageCorpconversationAsyncsendV2Request.Link());
				msg.getLink().setTitle(msgTitle);
				msg.getLink().setText(msgContent);
				msg.getLink().setMessageUrl(messageUrl);
				msg.getLink().setPicUrl(picUrl);
				request.setMsg(msg);
				break;
			// case "markdown":
			// msg.setMsgtype(EnumDingtalkMsgType.markdown.getValue());
			// msg.setMarkdown(new
			// OapiMessageCorpconversationAsyncsendV2Request.Markdown());
			// msg.getMarkdown().setText("##### text");
			// msg.getMarkdown().setTitle("### Title");
			// request.setMsg(msg);
			// break;
			// case "oa":
			// msg.setMsgtype(EnumDingtalkMsgType.oa.getValue());
			// msg.setOa(new
			// OapiMessageCorpconversationAsyncsendV2Request.OA());
			// msg.getOa().setHead(new
			// OapiMessageCorpconversationAsyncsendV2Request.Head());
			// msg.getOa().getHead().setText("head");
			// msg.getOa().setBody(new
			// OapiMessageCorpconversationAsyncsendV2Request.Body());
			// msg.getOa().getBody().setContent("xxx");
			// request.setMsg(msg);
			// break;
			// case "action_card":
			// msg.setMsgtype(EnumDingtalkMsgType.action_card.getValue());
			// msg.setActionCard(new
			// OapiMessageCorpconversationAsyncsendV2Request.ActionCard());
			// msg.getActionCard().setTitle("xxx123411111");
			// msg.getActionCard().setMarkdown("### 测试123111");
			// msg.getActionCard().setSingleTitle("测试测试");
			// msg.getActionCard().setSingleUrl("https://www.baidu.com");
			// request.setMsg(msg);
			// break;
			default:
				break;
			}
			OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(response.getBody());
			return jb;
		} catch (ApiException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取回调失败的结果
	 * 获取成功后，钉钉会立即删除已返回数据，需要做好平台本地保存，一面数据丢失
	 * @param accessToken
	 * @return
	 */
	public static JSONObject getCallBackFailedResult(String accessToken) {
		try {
			DingTalkClient client = new DefaultDingTalkClient(DingTalkApis.URI_GET_CALL_BACK_FAILED_RESULT);
			OapiCallBackGetCallBackFailedResultRequest req = new OapiCallBackGetCallBackFailedResultRequest();
			req.setHttpMethod("GET");
			OapiCallBackGetCallBackFailedResultResponse rsp = client.execute(req, accessToken);
			JSONObject jb = DingtalkUtils.getJsonResult(rsp.getBody());
			return jb;
		} catch (ApiException e) {
			e.printStackTrace();
		}
		return null;
	}

}
